home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / audio / somePlayback / someWaves.c < prev   
Encoding:
C/C++ Source or Header  |  1994-08-02  |  33.5 KB  |  1,090 lines

  1. /*
  2.  * Copyright 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*********************************************************************** 
  18.  *
  19.  * someWaves.c:    code to generate a bunch of oscillators, waveforms, 
  20.  *            change playback rate, mix them and send them to speaker.
  21.  *
  22.  * SpecifyLoopType:        set loop to off, forward, backward or forward/backward
  23.  * ResetOscillator:        reset oscillator to play from beginning.
  24.  * InitAL:            create,initialize an AL output port.
  25.  * CreateOscillator:        create and initialize oscillator data structure
  26.  * RunOscillator:        play data with loops.
  27.  * MixOutputBuffers:        mix specified number of output buffers in equal
  28.  *                proportion.
  29.  * SetPlaybackRatio:        specify ratio: playback rate/original sampling rate
  30.  * SetPlaybackEqualTemperedRatio:    specify ratio: playback rate/original sampling 
  31.  *                rate in equal-tempered units of half steps and cents.
  32.  * GenerateSawtoothWave:    generate non-bandlimited sawtooth wave. 
  33.  * GenerateTriangleWave:    generate non-bandlimited triangle wave. 
  34.  * GeneratePulseWave:        generate non-bandlimited pulse wave of specified duty cycle. 
  35.  * GenerateWave:        generate general wave as sum of of cosines of specified 
  36.  *                length.  
  37.  * InterleaveShorts:        interleave two buffers (of equal length) of shorts
  38.  *                into a single buffer of shorts.
  39.  * DestroyOscillator:        destroy oscillator data structure
  40.  *
  41.  *                Written by Gints Klimanis
  42.  *            Silicon Graphics Computer Systems
  43.  *                     1992
  44.  *                gints@roadkill.esd.sgi.com
  45.  *
  46.  *    This code is public domain.  I am not responsible for inaccuracies
  47.  *    in code, comments or theory. This code was written in early
  48.  *    morning hours.
  49.  *
  50.  *
  51. Makefile
  52. SHELL = /bin/sh
  53. CFLAGS = -O2 -cckr -float
  54. ALL= someSawtoothWaves someSquareWaves somePulseWaves somePulseWidthModulatedWaves someCoolWaves
  55.  
  56. all: $(ALL)
  57.  
  58. someSawtoothWaves:       someWaves.o
  59.     $(CC) -DSAWTOOTH_WAVE $(CFLAGS) -c someWaves.c
  60.     $(CC) -o $@ someWaves.o -laudio -laudiofile -lm -lmalloc
  61.  
  62. someSquareWaves:       someWaves.o
  63.     $(CC) -DSQUARE_WAVE $(CFLAGS) -c someWaves.c
  64.     $(CC) -o $@ someWaves.o -laudio -laudiofile -lm -lmalloc
  65.  
  66. somePulseWaves:       someWaves.o
  67.     $(CC) -DPULSE_WAVE $(CFLAGS) -c someWaves.c
  68.     $(CC) -o $@ someWaves.o -laudio -laudiofile -lm -lmalloc
  69.  
  70. somePulseWidthModulatedWaves:       someWaves.o
  71.     $(CC) -DPULSE_WAVE -DPULSE_WIDTH_MODULATION $(CFLAGS) -c someWaves.c
  72.     $(CC) -o $@ someWaves.o -laudio -laudiofile -lm -lmalloc
  73.  
  74. someCoolWaves:       someWaves.o
  75.     $(CC) -DCOOL_WAVE $(CFLAGS) -c someWaves.c
  76.     $(CC) -o $@ someWaves.o -laudio -laudiofile -lm -lmalloc
  77.  
  78. clean:
  79.     rm -f *.o 
  80.  
  81. clobber: clean
  82.     rm -f $(ALL)
  83.  
  84.  *********************************************************************** */
  85. #include <stdio.h>
  86. #include <math.h>
  87. #include "audio.h"
  88. #include "audiofile.h"
  89. #include <sys/schedctl.h>
  90.  
  91. /* play module parameters */
  92. typedef struct oscillatordata {
  93.     int    loopType;        /* off, forward, backward, forward&backward */
  94.                         
  95.     int    goingForward;        /* current loop direction */
  96.     int    variSpeed;        /* TRUE if sample is to be played at rate other
  97.                     than original sampling rate */
  98.  
  99.     short    *sampleBase;        /* ptr to audio data */
  100.     int    sampleLength;        /* length of audio data */
  101.     int    sampleDone;         
  102.  
  103.     short    *outputBuffer;        /* ptr to oscillator output buffer */
  104.     int    outputBufferLength; /* length of oscillator output buffer */
  105.  
  106.     int    playSample;        /* current sample to write into output buffer */
  107.     double    playSampleDouble;   /* ditto, but for varispeed */
  108.     double    playIncrementDouble; /* distance to next sample */
  109.     }     OscillatorData;
  110.  
  111. /* loop directions */
  112. #define    LOOP_OFF                    1
  113. #define LOOP_FORWARD                2
  114. #define LOOP_BACKWARD                3
  115. #define LOOP_FORWARD_N_BACKWARD        4
  116.  
  117. #define FALSE 0
  118. #define TRUE 1
  119.  
  120. /* some Audio Library stuff */
  121. ALconfig     aconfig;
  122. ALport        outport;
  123.  
  124. /* some Audio File library stuf */
  125. AFfilesetup    newSetUp;
  126. AFfilehandle    sourceFile;
  127. int        writeToAudioFile = FALSE;
  128. char        sourceFileName[2000];
  129.  
  130. /* execution time = numBlocks*OUTPUT_BLOCK_SIZE/sampling rate
  131. Example:
  132.         668*2048/44100 = ~31 seconds
  133. */
  134. #define NUM_BLOCKS            668
  135. #define OUTPUT_BLOCK_SIZE        2048
  136. #define SAMPLING_RATE            44100
  137. double    samplingRate = (double)SAMPLING_RATE;
  138. int    numBlocks = NUM_BLOCKS;
  139.  
  140. #define MAX_OSCILLATORS            32
  141. /* don't set NUM_OSCILLATORS < 4 oscillators */
  142. #define NUM_OSCILLATORS            16
  143. #define NUM_WAVES            2000
  144. int pitchSlideOn = 1;            /* enables pitch slide */
  145. double pitchInHertz = 55.0;        /* initial pitch of wave, subject to pitch slide */
  146.  
  147. static char someWavesUsage[] 
  148.     = 
  149. "\t\t-help\n \
  150. \t\t-time (seconds > 0) default: 10\n\
  151. \t\t<output file name>";
  152.  
  153. /* 
  154.  * SpecifyLoopType:     set loop to off, forward, backward or forward/backward
  155.  *
  156.  * ---------------------------------------------------------------------- */
  157.     void
  158. SpecifyLoopType(OscillatorData *data, int loopType)
  159. {
  160. switch (loopType)
  161.     {
  162.     case LOOP_OFF:
  163.     data->loopType = loopType;
  164.      break;
  165.     case LOOP_FORWARD:
  166.     data->loopType = loopType;
  167.     data->goingForward = TRUE;
  168.     break;
  169.     case LOOP_BACKWARD:
  170.     data->loopType = loopType;
  171.     data->goingForward = FALSE;
  172.     break;
  173.     case LOOP_FORWARD_N_BACKWARD:
  174.     data->loopType = loopType;
  175.     break;
  176.     default:
  177.     fprintf(stderr, "SpecifyLoopType(): bogus loop type %d.\n", loopType);
  178.     }
  179. }    /* ----------------------- end SpecifyLoopType() --------------------- */
  180.  
  181. /* 
  182.  * ResetOscillator:     reset oscillator to play from beginning.
  183.  *
  184.  * ---------------------------------------------------------------------- */
  185.     void 
  186. ResetOscillator(OscillatorData *data)
  187. {
  188. if (data != NULL)   
  189.     {
  190.     /* start at beginning of sample */
  191.     data->playSample = 0;
  192.     data->playSampleDouble = 0.0;
  193.     data->sampleDone = FALSE;
  194.     data->goingForward = TRUE;
  195.     }
  196. }    /* ----------------------- end ResetOscillator() --------------------- */
  197.  
  198. /*
  199.  * InitAL:  create,initialize an AL output port.
  200.  * -------------------------------------------------------------------- */
  201.     void
  202. InitAL()
  203. {
  204. long pvbuf[2];
  205.  
  206. /* get new ALconfiguration */        
  207.     aconfig = ALnewconfig();
  208. /* fill new ALconfiguration */
  209.     ALsetqueuesize(aconfig, SAMPLING_RATE); /* one second at selected sampling rate */
  210.     ALsetwidth(aconfig, AL_SAMPLE_16);
  211.     ALsetchannels(aconfig, AL_STEREO);
  212.  
  213. /* open a new ALport with the ALconfiguration */
  214.     outport = ALopenport("xxx", "w", aconfig);
  215.     if ((outport == (ALport)0) || (outport == (ALport)-1))
  216.     {
  217.       fprintf(stderr,"InitAL(): failed to open audio write port\n");
  218.       return;
  219.     }
  220.  
  221. /* set hardware sampling rate */
  222. pvbuf[0] = AL_OUTPUT_RATE;
  223. pvbuf[1] = SAMPLING_RATE,
  224. ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2);
  225. }    /* ----------------------- end InitAL() --------------------- */
  226.  
  227. /*
  228.  * CreateOscillator:  create and initialize oscillator data structure
  229.  * -------------------------------------------------------------------- */
  230.     OscillatorData *
  231. CreateOscillator()
  232. {
  233. int i;
  234. OscillatorData *tmpData;
  235.  
  236. /* set up play back structure */
  237. tmpData = (OscillatorData *) malloc(sizeof(OscillatorData));
  238. if (tmpData != NULL)
  239.     {
  240.     /* allocate oscillator output buffer */
  241.     tmpData->outputBufferLength = OUTPUT_BLOCK_SIZE;
  242.     tmpData->outputBuffer = (short *) malloc(OUTPUT_BLOCK_SIZE*sizeof(short));
  243.     if (tmpData->outputBuffer == NULL)
  244.     {
  245.     free(tmpData);
  246.     return (NULL);
  247.     }
  248.     
  249.     ResetOscillator(tmpData);
  250.     tmpData->playIncrementDouble = 1.0;        /* playback at original sampling rate */
  251.     tmpData->variSpeed = TRUE;            /* assume playback ratio will change later */
  252.     SpecifyLoopType(tmpData, LOOP_FORWARD); /* loop forward */
  253.     }
  254. else
  255.     return (NULL);
  256.  
  257. return (tmpData);
  258. }    /* ----------------------- end CreateOscillator() --------------------- */
  259.  
  260. /* 
  261.  * RunOscillator:   play data with loops.
  262.  *            Assume one data buffer of type short.  includes sampling 
  263.  *            rate conversion via truncated fractional counter.
  264.  *            This is among the least effective of sampling rate converters.
  265.  *            However, the method requires minimum compute power.
  266.  *            
  267.  *            With a double precision counter,  frequency
  268.  *            precision decreases with length of the audio sample.
  269.  *            Practically, it's not a problem, since a sample
  270.  *            with a 31-bit length takes 12 hours to play (at 44100
  271.  *            samples/second), yielding a frequency precision
  272.  *            of 21-bits.   
  273.  *
  274.  *            This routine loops the ENTIRE sample.  Code here is a
  275.  *            simple example.
  276.  *
  277.  * ---------------------------------------------------------------------- */
  278.     void 
  279. RunOscillator(OscillatorData *data)
  280. {
  281.     register long        i;
  282.     register short        *output;        /* ptr to output buffer */
  283.     register short        *sampleBase;
  284.     register int        end, index, goingForward, playSample;
  285.     register double        playSampleDouble, playIncrementDouble;
  286.  
  287. if (data != NULL)
  288. {
  289. /* load parameters */
  290.     sampleBase = data->sampleBase;
  291.     end = data->sampleLength;
  292.  
  293.   /* 
  294.    * ------------------------------ perform play
  295.    */
  296.     output = data->outputBuffer;
  297.     i = data->outputBufferLength+1;
  298. /* 
  299.  * compute output at sampling rate not equal to original 
  300.  */
  301. if (data->variSpeed == TRUE)
  302.     {
  303.     playSampleDouble = data->playSampleDouble;    
  304.     playIncrementDouble = data->playIncrementDouble;
  305.     switch (data->loopType)
  306.     {
  307.     case LOOP_OFF:
  308.         if (data->sampleDone == FALSE)
  309.         {
  310.           for (; --i > 0; output++) 
  311.             {
  312.             index = (int) playSampleDouble;
  313.             if (index >= end)
  314.             break;
  315.             output[0] = sampleBase[index]; 
  316.             playSampleDouble += playIncrementDouble;
  317.             }
  318.         if (index >= end)
  319.             data->sampleDone = TRUE;
  320.         }
  321.  
  322.     /* sample is done: output zero-valued samples to rest of buffer */
  323.       for (; --i > 0; output++) 
  324.         output[0] = 0.0;
  325.     break;
  326.  
  327.     case LOOP_FORWARD:
  328.         index = (int) playSampleDouble;
  329.       for (; --i > 0; output++) 
  330.         {  
  331.         output[0] = sampleBase[index];
  332.  
  333.         playSampleDouble += playIncrementDouble;
  334.         index = (int) playSampleDouble;
  335.         if (index >= end)
  336.         {
  337.         index = 0;
  338.         playSampleDouble -= (double) end;
  339.         }
  340.         }
  341.     break;
  342.  
  343.     case LOOP_BACKWARD:
  344.         index = (int) playSampleDouble;
  345.       for (; --i > 0; output++) 
  346.         {
  347.         output[0] = sampleBase[index];
  348.         playSampleDouble -= playIncrementDouble;
  349.         if (index < 0)
  350.         {
  351.         index = end;
  352.         playSampleDouble += (double) end;
  353.         }
  354.           }
  355.     break;
  356.  
  357.     case LOOP_FORWARD_N_BACKWARD:
  358.         goingForward = data->goingForward;
  359.         index = (int) playSampleDouble;
  360.       for (; --i > 0; output++) 
  361.         {
  362.         /* do forward thang */
  363.         if (goingForward == TRUE)
  364.         {
  365.         output[0] = sampleBase[index];
  366.         playSampleDouble += playIncrementDouble;
  367.         index = (int) playSampleDouble;
  368.     
  369.         /* careful about mirror-around points */
  370.         if (index >= end)
  371.             {
  372.             playSampleDouble = ((double) (end + end)) - playSampleDouble;
  373.             goingForward = FALSE;
  374.             }
  375.         }
  376.         /* do backward thang */
  377.         else
  378.         {
  379.         output[0] = sampleBase[index];
  380.         playSampleDouble -= playIncrementDouble;
  381.         index = (int) playSampleDouble;
  382.     
  383.         /* careful about mirror-around points */
  384.         if (index < 0)
  385.             {
  386.             playSampleDouble = -playSampleDouble;
  387.             goingForward = TRUE;
  388.             }
  389.         }
  390.           }
  391.     /* save loop direction status */
  392.         data->goingForward = goingForward;
  393.     break;
  394.  
  395.     default:
  396.     fprintf(stderr,"RunOscillator(): bogus loopType %d\n", data->loopType);
  397.     return;
  398.     }
  399. /* save parameters */
  400.     data->playSampleDouble = playSampleDouble;
  401.     }
  402. /* 
  403.  * compute output at sampling rate equal to original.  This requires less CPU time. 
  404.  */
  405. else
  406.     {
  407.     playSample = data->playSample; 
  408.     switch (data->loopType)
  409.     {
  410.     case LOOP_OFF:
  411.         if (data->sampleDone == FALSE)
  412.         {
  413.           for (; (playSample < end)&&(--i > 0); output++) 
  414.             {
  415.             output[0] = sampleBase[playSample++];
  416.             }
  417.         if (playSample >= end)
  418.             data->sampleDone = TRUE;
  419.         }
  420.  
  421.     /* now output zero-valued samples */
  422.       for (; --i > 0; output++) 
  423.         {
  424.         output[0] = 0.0;
  425.         }
  426.     break;
  427.  
  428.     case LOOP_FORWARD:
  429.       for (; --i > 0; output++) 
  430.         {  
  431.         output[0] = sampleBase[playSample++];
  432.     
  433.         if (playSample >= end)
  434.         playSample = 0;
  435.         }
  436.     break;
  437.  
  438.     case LOOP_BACKWARD:
  439.       for (; --i > 0; output++) 
  440.         {
  441.         output[0] = sampleBase[playSample--];
  442.     
  443.         if (playSample < 0)
  444.         playSample = end;
  445.           }
  446.     break;
  447.  
  448.     case LOOP_FORWARD_N_BACKWARD:
  449.         goingForward = data->goingForward;
  450.       for (; --i > 0; output++) 
  451.         {
  452.         if (goingForward == TRUE)
  453.         {
  454.         output[0] = sampleBase[playSample++];
  455.     
  456.         if (playSample >= end)
  457.             goingForward = FALSE;
  458.         }
  459.         else
  460.         {
  461.         output[0] = sampleBase[--playSample];
  462.     
  463.         if (playSample <= 0)
  464.             goingForward = TRUE;
  465.         }
  466.           }
  467.     /* save loop direction status */
  468.         data->goingForward = goingForward;
  469.     break;
  470.  
  471.     default:
  472.         fprintf(stderr,"RunOscillator(): bogus loopType %d\n", data->loopType);
  473.         return;
  474.     }
  475. /* save parameters */
  476.     data->playSample = playSample;
  477.     }
  478. }
  479. }    /* ----------------------- end RunOscillator() --------------------- */
  480.  
  481. /*
  482.  * MixOutputBuffers:  mix specified number of output buffers in equal
  483.  *            proportion.
  484.  * -------------------------------------------------------------------- */
  485.     void
  486. MixOutputBuffers(OscillatorData *data[], short *finalMix, int totalBuffers)
  487. {
  488. int        i, j;
  489. int        mix;    /* 32 bit mixer to avoid intermediate overflow during mix */
  490. short        *finalMixPtr;
  491.  
  492. /*
  493.  * mix an arbitrary # of buffers.  This routine is GENERAL.  You will gain
  494.  * more performance by coding for the # of buffers you need.
  495.  */
  496. finalMixPtr = finalMix;
  497. for (i = 0; i < OUTPUT_BLOCK_SIZE; i++)
  498.     {
  499.     mix = 0;
  500.     for (j = 0; j < totalBuffers; j += 2)
  501.     {
  502.     mix += (int) data[j]->outputBuffer[i];
  503.     }
  504.     /* grossly scale output such that no overflow occurs */
  505.     /* alternative: saturation.  */
  506.     *finalMixPtr++ = (short) (mix/(totalBuffers/2));
  507.     }
  508. }    /* ----------------------- end MixOutputBuffers() --------------------- */
  509.  
  510. /*
  511.  * SetPlaybackRatio:    specify ratio: playback rate/original sampling rate
  512.  * -------------------------------------------------------------------- */
  513.     void
  514. SetPlaybackRatio(OscillatorData *data, double ratio)
  515. {
  516. if (data != NULL)
  517.     data->playIncrementDouble = ratio;
  518. }    /* ----------------------- end SetPlaybackRatio() --------------------- */
  519.  
  520. /*
  521.  * SetPlaybackEqualTemperedRatio:    specify ratio: playback rate/original sampling 
  522.  *                    rate in equal-tempered units of half steps and cents.
  523.  * -------------------------------------------------------------------- */
  524.     void
  525. SetPlaybackEqualTemperedRatio(OscillatorData *data, int halfSteps, int cents)
  526. {
  527. double        pitchChange;
  528.  
  529. /* a half step is the difference in pitch between two adjacent notes on, for
  530.     example, a piano. A cent is 1/100 of a half step.   This function is
  531.     pricey for pitch computing.  Might be a better idea to store a collection
  532.     of these values in a table. */
  533. if (data != NULL)
  534.     {
  535.     /* add half steps and cents and compute 2^(frequency/12) */
  536.     pitchChange = ((double) halfSteps) + (((double) cents)/100.0);
  537.     data->playIncrementDouble = pow(2.0, pitchChange/12.0);
  538.     }
  539. }    /* ----------------------- end SetPlaybackEqualTemperedRatio() --------------------- */
  540.  
  541. /*
  542.  * GenerateSawtoothWave:    generate non-bandlimited sawtooth wave. 
  543.  * -------------------------------------------------------------------- */
  544.     void
  545. GenerateSawtoothWave(short *waveMemory, int length)
  546. {
  547. int    i;
  548. double    arg, argInc;
  549.  
  550.     /* 
  551.      * compute sawtooth wave.  This process generates a wave with all harmonics
  552.      *    with amplitude proportional to 1/harmonic #.          
  553.      */
  554.     arg = 32767.0;
  555.     argInc = 32767.0/((double) length);
  556.     for (i = 0; i < length; i++, arg -= argInc)
  557.     waveMemory[i] = (short) arg;
  558. }    /* ----------------------- end GenerateSawtoothWave() --------------------- */
  559.  
  560. /*
  561.  * GenerateTriangleWave:    generate non-bandlimited triangle wave. 
  562.  * -------------------------------------------------------------------- */
  563.     void
  564. GenerateTriangleWave(short *waveMemory, int length)
  565. {
  566. int    i;
  567. double    arg, argInc;
  568.  
  569.     /* 
  570.      * compute triangle wave.  This process generates a wave with odd harmonics
  571.      *    with amplitude proportional to 1/(harmonic # squared).          
  572.      */
  573.     arg = -32767.0;
  574.     argInc = 4.0*32767.0/((double) length);
  575.     /* do positive slope portion */
  576.     for (i = 0; (i < length)&&(arg <= 32767.0); i++, arg += argInc)
  577.     waveMemory[i] = (short) arg;
  578.  
  579.     /* do negative slope portion */
  580.     arg = 2.0*32767.0 - arg;    /* mirror xtra back into range */
  581.     for (; i < length; i++, arg -= argInc)
  582.     waveMemory[i] = (short) arg;
  583. }    /* ----------------------- end GenerateTriangleWave() --------------------- */
  584.  
  585. /*
  586.  * GeneratePulseWave:    generate non-bandlimited pulse wave of specified duty cycle. 
  587.  * -------------------------------------------------------------------- */
  588.     void
  589. GeneratePulseWave(short *waveMemory, int length, int dutyCycleEnd)
  590. {
  591. int    i;
  592.  
  593. /* check for valid duty cycle Range:  2..length-2 */
  594. if ((dutyCycleEnd <= 1)||(dutyCycleEnd >= length-1))
  595.     {
  596.     fprintf(stderr, "GeneratePulse(): bogus duty cycle end %d.  No wave, dude\n", dutyCycleEnd);
  597.     return;
  598.     }
  599.  
  600.     /* Here, duty cycle is percentage of wavelength signal positive. 
  601.      * Duty cycle specifies the harmonic relationships.  A pulse function in the
  602.      * time domain transforms into a sin(x)/x or sinc(x) function in the
  603.      * frequency domain.  The value of the sinc function will determine the
  604.      * amplitude of the harmonics.  
  605.      *
  606.      * A square wave (duty cycle 50%) is member of the pulse wave family.  Just 
  607.      * so happens that the frequency domain sinc function for the square wave 
  608.      * is zero at every even harmonic.  Thus, a square wave contains odd only
  609.      * harmonics whose amplitudes are 1/harmonic #.  
  610.      *
  611.      * A pulse wave with a 33% duty cycle is missing every third harmonic.
  612.      * A pulse wave with a 25% duty cycle is missing every fourth harmonic.
  613.      * And so on, and so on.   However, the present harmonics don't have a 
  614.      * simple 1/harmonic # amplitude relationship.  Need to examin the sinc function.
  615.      * Very small and very large duty cycles have a nasal quality.
  616.      *
  617.      * A traditional method for producing ballsy sounds from a single oscillator
  618.      * is to modulate the duty cycle.  This can be done by computing 400 or so
  619.      * pulse waves with increasing duty cycles and cycling through this list of
  620.      * waves in a forward backward manner.  THIS IS TERMED PULSE WIDTH MODULATION.
  621.      * The more samples are in your wave, the thinner your thinnest pulse can be.
  622.      * 
  623.      * The modulation rate is determined by the rate at which the pulse widths change.
  624.      * This is determined by the rate at which the pulse wave set is stepped 
  625.      * thru and the number of different pulse waves in the set.
  626.      */
  627.  
  628.     /* do duty cycle portion */
  629.     for (i = 0; i < dutyCycleEnd; i++)
  630.     waveMemory[i] = 32767;    
  631.  
  632.     /*  do off portion */
  633.     for (; i < length; i++)
  634.     waveMemory[i] = -32767;
  635. }    /* ----------------------- end GeneratePulseWave() --------------------- */
  636.  
  637. /*
  638.  * GenerateWave:    generate general wave as sum of of cosines of specified 
  639.  *            length.  
  640.  * -------------------------------------------------------------------- */
  641.     void
  642. GenerateWave(short *waveMemory, int length)
  643. {
  644. int        i, j;
  645. double        arg, argInc;
  646. int        someNumber;
  647. int        numberOfHarmonics = 99;
  648. double        amplitude[500];
  649. int        phase[500];
  650. double        *cosineTable;
  651. int        cosineIndex, cosineIncrement;
  652. double        maxValue, someDouble;
  653. double        *wave;
  654.  
  655.     /* allocate memory for cosine table, intermediate storage and final product */
  656.     cosineTable = (double *) malloc(length*sizeof(double));
  657.     if (cosineTable == NULL)
  658.     {
  659.     fprintf(stderr,"GenerateWave(): failed to allocate cosineTable. No wave, dude.\n");
  660.     return;
  661.     }
  662.     wave = (double *) malloc(length*sizeof(double));
  663.     if (wave == NULL)
  664.     {
  665.     fprintf(stderr,"GenerateWave(): failed to allocate intermediate memory. No wave, dude.\n");
  666.     free(cosineTable);
  667.     return;
  668.     }
  669.  
  670.      /* generate a full cycle of a cosine table */
  671.     argInc = (8.0*atan(1.0))/((double) (length));   /* 2*PI/wavelength */
  672.     arg = 0.0;
  673.     for (i = 0; i < length; i++, arg += argInc)
  674.        cosineTable[i] = cos(arg);
  675.  
  676.     /* initialize harmonic amplitude array.  */
  677.     for (i = 1; i <= numberOfHarmonics; i+=5)
  678.     {
  679.     amplitude[i] = 1.0/((double) i);  
  680.     amplitude[i+1] = 0.0; 
  681.     amplitude[i+2] = 0.0; 
  682.     amplitude[i+3] = 0.0; 
  683.     amplitude[i+4] = 0.0; 
  684.     }
  685.  
  686.     /* initialize harmonic phase array. Phase must be in range
  687.         0..length-1 */
  688.     for (i = 1; i <= numberOfHarmonics; i++)
  689.     phase[i] = 0;  
  690.  
  691.    /* clear wave memory */
  692.     for (i = 0; i < length; i++)
  693.         wave[i] = 0.0;
  694.  
  695.     /* generate wave with specified # harmonics */
  696.     for (i = 1; i <= numberOfHarmonics; i++)
  697.     {
  698.     if (amplitude[i] != 0.0)
  699.         {
  700.         cosineIncrement = i;
  701.         /*cosineIndex = phase[i];*/
  702.         cosineIndex = 0;
  703.         for (j = 0; j < length; j++)
  704.         {
  705.         wave[j] += amplitude[i]*cosineTable[cosineIndex];
  706.         cosineIndex += cosineIncrement;
  707.         /* bound cosine table index to actual table */
  708.         if (cosineIndex >= length)
  709.             cosineIndex -= length;
  710.         }
  711.         }
  712.     }
  713.  
  714.     /* find largest value in wave */
  715.     maxValue = 0.0;
  716.     for (i = 0; i < length; i++)
  717.         {
  718.         someDouble = wave[i];
  719.         if (someDouble < 0.0)
  720.         someDouble = -someDouble;
  721.         if (someDouble > maxValue)
  722.         maxValue = someDouble;
  723.         }
  724.  
  725.     /* write into sample memory.  Product is fit in range -32768..32767 */
  726.     maxValue = 32767.0/maxValue;    /* normalization factor */
  727.     for (i = 0; i < length; i++)
  728.         waveMemory[i] = (short) (maxValue*wave[i]);
  729.  
  730.     free(cosineTable);
  731.     free(wave);
  732. }    /* ----------------------- end GenerateWave() --------------------- */
  733.  
  734. /*
  735.  * InterleaveShorts:    interleave two buffers (of equal length) of shorts
  736.  *            into a single buffer of shorts.
  737.  * -------------------------------------------------------------------- */
  738.     void
  739. InterleaveShorts(short *inBufferLeft, short *inBufferRight, short *outBuffer, int inBufferLength)
  740. {
  741. register int    i;
  742. register short    *inLeftPtr, *inRightPtr, *outPtr;
  743.  
  744. inLeftPtr = inBufferLeft;
  745. inRightPtr = inBufferRight;
  746. outPtr = outBuffer;
  747. /* output buffer shold not be either of input buffers */
  748. for (i = inBufferLength+1; --i > 0; inLeftPtr++, inRightPtr++, outPtr+=2)
  749.     {
  750.     outPtr[0] = inLeftPtr[0];
  751.     outPtr[1] = inRightPtr[0];
  752.     }
  753. }    /* ----------------------- end InterleaveShorts() --------------------- */
  754.  
  755. /*
  756.  * DestroyOscillator:    destroy oscillator data structure
  757.  * -------------------------------------------------------------------- */
  758.     void
  759. DestroyOscillator(OscillatorData *data)
  760. {
  761. if (data != NULL)
  762.     {
  763.     /* free sound memory */
  764.     if (data->sampleBase != NULL)
  765.     free(data->sampleBase);
  766.     free(data);
  767.     }
  768. }    /* ----------------------- end DestroyOscillator() --------------------- */
  769.  
  770. /* **********************************************************************
  771.  * ParseCommandLine:    parse input command line for user options  
  772.  * ********************************************************************** */
  773.     static void
  774. ParseCommandLine(int argc, char **argv)
  775. {
  776. int        i;
  777. char        *s;
  778. double        outputTime;
  779.  
  780. for (i = 1; i < argc; i++)
  781.     {
  782.     /* check for -t or -time argument */
  783.     if (!strncmp(argv[i], "-t", sizeof("-t")-1))
  784.     {
  785.     s = argv[++i];
  786.     if (!isdigit(s[0]))
  787.         {
  788.         fprintf(stderr, "Usage: %s\n", someWavesUsage);
  789.         exit(1);
  790.         }
  791.     outputTime = atof(s);
  792.     if (outputTime <= 0.0)
  793.         exit(1);        
  794.     /* compute#blocks of OUTPUT_BLOCK_SIZE to be synthesized */
  795.     numBlocks = (0.5+outputTime*samplingRate/((double) OUTPUT_BLOCK_SIZE));
  796.     }
  797.     /* check for -h or -help */
  798.     else if (!strncmp(argv[i], "-h", sizeof("-h")-1))
  799.     {
  800.     fprintf(stderr, "Usage: %s\n", someWavesUsage);
  801.     exit(1);
  802.     }
  803.     /* ah, must be a file name */
  804.     else if (argv[i][0] != '\0')
  805.     {
  806.     strcpy(sourceFileName, argv[i]);
  807.     writeToAudioFile = TRUE;
  808.     }
  809.     }
  810. }    /* ----------------------- end ParseCommandLine() --------------------- */
  811.  
  812. /*
  813.  * main:        crank out some cool sounds
  814.  * -------------------------------------------------------------------- */
  815. main(int argc, char **argv)
  816. {
  817. int        i, j;
  818. OscillatorData    **someData;
  819. short        *mixLeft, *mixRight, *finalMix;
  820. short        *waveMemory;
  821. int        waveLength;
  822. int        pulseIndex, pulseWidth, pulseIncrement, numPulseWaves;
  823. int        pulseDataEnd;
  824. int        stereoSpread;
  825. int        done;
  826. double        pitchMultiplier;
  827. int        blockCount;
  828. int        mainPid;
  829.  
  830. /* sampling rate / frequency of resultant waveform */
  831. waveLength = samplingRate/(2.0*pitchInHertz); 
  832.  
  833. /* execution time = numBlocks*OUTPUT_BLOCK_SIZE/sampling rate
  834. Example:
  835.         668*2048/44100 = ~31 seconds
  836. */
  837. numBlocks = (0.5+10.0*samplingRate/((double) OUTPUT_BLOCK_SIZE));
  838. ParseCommandLine(argc, argv);
  839.  
  840. /*
  841.  * initialize setup structure for new file
  842.  */
  843. if (writeToAudioFile == TRUE)
  844.     {
  845.     newSetUp = AFnewfilesetup();
  846.     AFinitchannels(newSetUp, AF_DEFAULT_TRACK, 2);
  847.     AFinitrate(newSetUp, AF_DEFAULT_TRACK, samplingRate);
  848.  
  849.    /* open new file */
  850.    sourceFile = AFopenfile(sourceFileName, "w", newSetUp);
  851.    if (sourceFile == AF_NULL_FILEHANDLE)
  852.     {
  853.     fprintf(stderr, "couldn't open %s\n", sourceFileName);
  854.     exit(1);
  855.     }
  856.     }
  857. /* make main process of highest priority normal process, non-degrading priority */   
  858. mainPid = getpid();
  859. schedctl(NDPRI, mainPid, NDPNORMMAX);
  860.  
  861. /* 
  862.  * allocate some memory 
  863.  */
  864. someData = (OscillatorData **) malloc(MAX_OSCILLATORS*sizeof(OscillatorData));
  865. mixLeft = (short *) malloc(OUTPUT_BLOCK_SIZE*sizeof(short));
  866. mixRight = (short *) malloc(OUTPUT_BLOCK_SIZE*sizeof(short));
  867. finalMix = (short *) malloc(2*OUTPUT_BLOCK_SIZE*sizeof(short));
  868. waveMemory = (short *) malloc(NUM_WAVES*waveLength*sizeof(short));
  869. if ((someData == NULL)||(mixLeft == NULL)||(mixRight == NULL)||
  870.     (finalMix == NULL)||(waveMemory == NULL))
  871.     {
  872.     fprintf(stderr, "main(): no memory available.  Exiting. \n");
  873.     exit (-1);
  874.     }
  875. /* 
  876.  * choose from this plethora of wave generation functions 
  877.  */
  878. #ifdef SAWTOOTH_WAVE
  879. GenerateSawtoothWave(waveMemory, waveLength);
  880. #endif
  881. #ifdef PULSE_WAVE
  882. GeneratePulseWave(waveMemory, waveLength, 10);    
  883. #endif
  884. #ifdef SQUARE_WAVE
  885. GeneratePulseWave(waveMemory, waveLength, waveLength/2);    
  886. #endif
  887. #ifdef COOL_WAVE
  888. GenerateWave(waveMemory, waveLength);
  889. #endif
  890. #ifdef TRIANGLE_WAVE
  891. GenerateTriangleWave(waveMemory, waveLength);
  892. #endif
  893.  
  894. /* 
  895.  * generate collection of pulse waves for pulse width modulation.
  896.  */  
  897. /* Keep track of number of pulse waves actually generated. Most extreme
  898.     pulse widths skipped because they are DC. # of waves generated depends
  899.     on variable waveLength */
  900. /* ALSO TRY GENERATING OTHER SETS OF RELATED WAVES USING GenerateWave() */
  901. #ifdef PULSE_WIDTH_MODULATION
  902.     numPulseWaves = 0;
  903.     for (i = 0, pulseWidth=2; pulseWidth < (waveLength-1); pulseWidth++, i++)
  904.     {
  905.     GeneratePulseWave(&waveMemory[i*waveLength], waveLength, pulseWidth);    
  906.     numPulseWaves++;
  907.     }
  908.     /* init pulse width parameters */
  909.     pulseIndex = 0*waveLength;    /* start at duty cycle 2 */
  910.     pulseIncrement = waveLength;
  911.     pulseDataEnd = (numPulseWaves-1)*waveLength;
  912. #endif
  913.  
  914. /* set up audio port */
  915. InitAL();
  916.  
  917. /*
  918.  *  --------------------------- create oscillators 
  919.  */
  920. for (i = 0; i < MAX_OSCILLATORS; i++)   
  921.     {
  922.     someData[i] = CreateOscillator();
  923.     if (someData[i] == NULL)
  924.     {
  925.     fprintf(stderr, "main():  failed to create voice %d.  Exiting. \n");
  926.     exit (-1);
  927.     }
  928.     /*  tell oscillator where to get wave data.  Specify length of data.  Could
  929.     also load data from a file  */
  930.     someData[i]->sampleLength = waveLength; 
  931.     someData[i]->sampleBase = waveMemory;
  932.      
  933.     /* specify loop type.  Have choice of LOOP_OFF, LOOP_FORWARD, LOOP_BACKWARD,
  934.     LOOP_FORWARD_N_BACKWARD */
  935.     SpecifyLoopType(someData[i], LOOP_FORWARD);
  936.  
  937.     /* turn varispeed on if playback rates will differ from original sampling rate */
  938.     someData[i]->variSpeed = TRUE;
  939.  
  940.     /* tell oscillator to start playing at beginning of wave */
  941.     ResetOscillator(someData[i]);
  942.     }
  943.  
  944. /* 
  945.  *    8 oscillators are used to play each waveform.  Two oscillators
  946.  *    playing the same audio at two slightly different rates (different tunings)
  947.  *    produce amplitude "beating" among the harmonics.
  948.  *    For waves with a rich harmonic spectrum, this beating yields a fatter
  949.  *    sound.  This difference in playback rate is termed detuning.  More detuned
  950.  *    oscillators yield a fatter sound.
  951.  *
  952.  *    In example below, an A=55 Hz waveform is played back with two
  953.  *    groups of 4 oscillators.  The first plays at A=55/2 (-12 semitones)
  954.  *    and the second plays at A=55/4 (-24 semitones).   So a total of
  955.  *    eight oscillators play in the left channel and the right channel.
  956.  *
  957.  *    Stereo is generated by playing the right channel a little faster than
  958.  *    the left channel.  This method for stereo generation adds well in mono.
  959.  *
  960.  *    Also note that the playback rate actually changes the time envelope and
  961.  *    the pitches.   Slower playback rates (< 1.0 or < 0 semitones) slow down
  962.  *    the time evolution of the spectrum and pitch shift the spectrum down.
  963.  *    Faster playback rates (> 1.0 or > 0 semitones) speed up
  964.  *    the time evolution of the spectrum and pitch shift the spectrum up.
  965.  *
  966.  *    Changes in playback rate using the suppiled pitch change method will generally cause
  967.  *    alising/imaging artifacts for large (> a few semitones) changes in the playback 
  968.  *    rate.   The method is simple.  More complex methods would reduce polyphony.
  969.  *
  970.  *    On IRIS Indigo:
  971.  *        At 44100 samples/second output rate, OPTIMIZER=02:
  972.  *        independent waveforms, indpendent loop type, independent playback rate
  973.  *            can do 21, mixed oscillators
  974.  *        independent waveforms, indpendent loop type, no change in playback rate
  975.  *            can do 26, mixed oscillators
  976.  * 
  977.  */
  978. /* 
  979.  * specify playback ratio of data 
  980.  */
  981. stereoSpread = 13;    /* playback rate difference between channels */
  982. /* left channel, higher note */
  983. SetPlaybackEqualTemperedRatio(someData[0], -12, 0);            
  984. SetPlaybackEqualTemperedRatio(someData[2], -12, 9);
  985. SetPlaybackEqualTemperedRatio(someData[4], -12, 18);
  986. SetPlaybackEqualTemperedRatio(someData[6], -12, 27);
  987. /* right channel, higher note */
  988. SetPlaybackEqualTemperedRatio(someData[1], -12, 0+stereoSpread);    
  989. SetPlaybackEqualTemperedRatio(someData[3], -12, 9+stereoSpread);
  990. SetPlaybackEqualTemperedRatio(someData[5], -12, 18+stereoSpread);
  991. SetPlaybackEqualTemperedRatio(someData[7], -12, 27+stereoSpread);
  992.  
  993. /* left channel, lower note */
  994. SetPlaybackEqualTemperedRatio(someData[8], -24, 0);
  995. SetPlaybackEqualTemperedRatio(someData[10], -24, 9);
  996. SetPlaybackEqualTemperedRatio(someData[12], -24, 18);
  997. SetPlaybackEqualTemperedRatio(someData[14], -24, 27);
  998. /* right channel, lower note */
  999. SetPlaybackEqualTemperedRatio(someData[9], -24, 0+stereoSpread);
  1000. SetPlaybackEqualTemperedRatio(someData[11], -24, 9+stereoSpread);
  1001. SetPlaybackEqualTemperedRatio(someData[13], -24, 18+stereoSpread);
  1002. SetPlaybackEqualTemperedRatio(someData[15], -24, 27+stereoSpread);
  1003.  
  1004. /* 
  1005.  * ------ generate numBlocks chunks of OUTPUT_BLOCK_SIZE
  1006.  */
  1007. for (blockCount = 0; blockCount < numBlocks; blockCount++)
  1008.     {
  1009.     /* compute NUM_OSCILLATORS.  */
  1010.     for (j = 0; j < NUM_OSCILLATORS; j++)
  1011.     if (someData[j] != NULL)
  1012.         RunOscillator(someData[j]);  
  1013.  
  1014.     /* mix oscillators with equal amplitudes */
  1015.     MixOutputBuffers(someData, mixLeft, NUM_OSCILLATORS/2);    
  1016.     MixOutputBuffers(&someData[1], mixRight, NUM_OSCILLATORS/2);
  1017.  
  1018.     /* interleave stereo data */
  1019.     InterleaveShorts(mixLeft, mixRight, finalMix, OUTPUT_BLOCK_SIZE);
  1020.  
  1021.     /* write data to AL audio port */
  1022.     ALwritesamps(outport, finalMix, 2*OUTPUT_BLOCK_SIZE);
  1023.  
  1024.     /* write to file */
  1025.     if (writeToAudioFile == TRUE)
  1026.     AFwriteframes(sourceFile, AF_DEFAULT_TRACK, finalMix, OUTPUT_BLOCK_SIZE);
  1027.  
  1028.     /* 
  1029.      *  Enabling pitch slide will cause the playback rate to increase 
  1030.      *  exponentially.  Pitch is exponentially related to the playback rate.
  1031.      *  This code has no bounds onaliasing, since that depends on the spectrum
  1032.      *  of your waveform.
  1033.      *  For pitch to increase, pitchMultiplier > 1
  1034.      *  For pitch to decrease, pitchMultiplier < 1
  1035.      */
  1036.     if (pitchSlideOn == TRUE)
  1037.     {
  1038.     pitchMultiplier = 1.001;
  1039.     for (j = 0; j < NUM_OSCILLATORS; j++)
  1040.         {
  1041.         someData[j]->playIncrementDouble *= pitchMultiplier;
  1042.     /* bound pitch increase */
  1043.         if        (someData[j]->playIncrementDouble < 0.0)
  1044.         someData[j]->playIncrementDouble = 0.0;
  1045.         else if (someData[j]->playIncrementDouble > 5.0)
  1046.         someData[j]->playIncrementDouble = 5.0;
  1047.         }
  1048.     }
  1049.  
  1050.     /* 
  1051.      * do pulse width modulation:  this code changes the waves for all oscillators
  1052.      * using the aforegenerated collection of pulse waves.  Listen to to waveform
  1053.      * change from thin/nasal to rich.  You can also hear the first few harmonics
  1054.      * fade in and out.  Probably only 3rd and 5th, since 2nd and 4th are covered
  1055.      * up since the notes are played in an interval of an octave.
  1056.      * Be sure that you don't forget to enable the generation of the pulse waves,
  1057.      * earlier in main().
  1058.      */
  1059. #ifdef PULSE_WIDTH_MODULATION
  1060.     pulseIndex += pulseIncrement;
  1061. #ifdef PULSE_WAVE
  1062.     if ((pulseIndex < 0)||(pulseIndex >= pulseDataEnd))
  1063.         {
  1064.         pulseIncrement = -pulseIncrement;
  1065.         if        (pulseIndex < 0)
  1066.         pulseIndex = -pulseIndex;
  1067.         else if (pulseIndex >= pulseDataEnd)
  1068.         pulseIndex = 2*pulseDataEnd - pulseIndex;
  1069.         }
  1070.     for (j = 0; j < NUM_OSCILLATORS; j++)
  1071.         someData[j]->sampleBase = &waveMemory[pulseIndex];
  1072. #endif
  1073. #endif
  1074.     }
  1075.  
  1076. /* close audio file */
  1077. if (writeToAudioFile == TRUE)
  1078.     AFclosefile(sourceFile);
  1079.  
  1080. /* wait until AL sample queue empties */
  1081. while (ALgetfilled(outport) > 0) 
  1082.     sginap(10);
  1083.  
  1084. /* when all is done, close AL port and free AL configuration */
  1085. ALcloseport(outport);
  1086. ALfreeconfig(aconfig);
  1087. }    /* ----------------------- end main() --------------------- */
  1088.  
  1089.  
  1090.